
#include "OperationMapper.h"

//------------------------
//--- OpearationMapper ---
//------------------------

using namespace ttg_internal;
using namespace ttg::math;

OperationMapper *OperationMapper::mapper = new OperationMapper();

OperationMapper::OperationMapper()
{
	for (int i1 = 0; i1 < 6; i1++)
		for (int i2 = 0; i2 < 4; i2++)
			for (int i3 = 0; i3 < 4; i3++)
				for (int i4 = 0; i4 < 4; i4++)
					opbase[i1][i2][i3][i4] = NULL;
	//UnaryPlus
	this->add(OperationInfo::UNARY_PLUS, new UnaryPlusOperation<float>(),
			  OperationInfo::TTGFLOAT);
	this->add(OperationInfo::UNARY_PLUS, new UnaryPlusOperation<vec3f>(),
			  OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::UNARY_PLUS, new UnaryPlusOperation<mat3x3f>(),
			  OperationInfo::TTGMATRIX4X4);
	//UnaryMinus
	this->add(OperationInfo::UNARY_MINUS, new UnaryMinusOperation<float>(),
			  OperationInfo::TTGFLOAT);
	this->add(OperationInfo::UNARY_MINUS, new UnaryMinusOperation<vec3f>(),
			  OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::UNARY_MINUS, new UnaryMinusOperation<mat4x4f>(),
			  OperationInfo::TTGMATRIX4X4);
	//Addition
	this->add(OperationInfo::ADDITION, new AddOperation<float>(),
			  OperationInfo::TTGFLOAT, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::ADDITION, new AddOperation<vec3f>(),
			  OperationInfo::TTGVECTOR3, OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::ADDITION, new AddOperation<mat4x4f>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGMATRIX4X4);
	//Substraction
	this->add(OperationInfo::SUBSTRACTION, new SubOperation<float>(),
			  OperationInfo::TTGFLOAT, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::SUBSTRACTION, new SubOperation<vec3f>(),
			  OperationInfo::TTGVECTOR3, OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::SUBSTRACTION, new SubOperation<mat4x4f>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGMATRIX4X4);
	//Multiplication
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<float, float>(),
			  OperationInfo::TTGFLOAT, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<vec3f, float>(),
			  OperationInfo::TTGVECTOR3, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<float, vec3f, vec3f>(),
			  OperationInfo::TTGFLOAT, OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<vec3f, vec3f>(),
			  OperationInfo::TTGVECTOR3, OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<mat4x4f, float>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<mat4x4f, vec3f, vec3f>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::MULTIPLICATION, new MulOperation<mat4x4f, mat4x4f>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGMATRIX4X4);
	//Division
	this->add(OperationInfo::DIVISION, new DivOperation<float, float>(),
			  OperationInfo::TTGFLOAT, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::DIVISION, new DivOperation<vec3f, float>(),
			  OperationInfo::TTGVECTOR3, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::DIVISION, new DivOperation<vec3f, vec3f>(),
			  OperationInfo::TTGVECTOR3, OperationInfo::TTGVECTOR3);
	this->add(OperationInfo::DIVISION, new DivOperation<mat4x4f, float>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGFLOAT);
	this->add(OperationInfo::DIVISION, new DivOperation<mat4x4f, mat4x4f>(),
			  OperationInfo::TTGMATRIX4X4, OperationInfo::TTGMATRIX4X4);
}

OperationMapper::~OperationMapper()
{
	for (int i1 = 0; i1 < 6; i1++)
		for (int i2 = 0; i2 < 4; i2++)
			for (int i3 = 0; i3 < 4; i3++)
				for (int i4 = 0; i4 < 4; i4++)
					if (opbase[i1][i2][i3][i4] != NULL)
						delete opbase[i1][i2][i3][i4];
}

OperationInfo *OperationMapper::get(OperationInfo::OperationName opname,
									OperationInfo::OperationType optype1,
									OperationInfo::OperationType optype2,
									OperationInfo::OperationType optype3)
{
	return mapper->opbase[opname][optype1][optype2][optype3];
}

OperationInfo *OperationMapper::create(OperationInfo::OperationName opname,
									   OperationInfo *op1,
									   OperationInfo *op2,
									   OperationInfo *op3)
{
	OperationInfo *ref = get(opname,
							 op1 != NULL ? op1->getType() : OperationInfo::UNKNOWN,
							 op2 != NULL ? op2->getType() : OperationInfo::UNKNOWN,
							 op3 != NULL ? op3->getType() : OperationInfo::UNKNOWN);
	if (ref != NULL)
		return ref->createInstance(op1, op2, op3);
	else
		return NULL;
}
